package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @Author: zm
 * @Date: 2021/8/24 20:38
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long submitOrder(OrderInfo orderInfo) {

        orderInfo.setOrderStatus(OrderStatus.UNPAID.name()); // 订单状态
        orderInfo.sumTotalAmount(); // 总价格

        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);

        List<OrderDetail> detailList = orderInfo.getOrderDetailList();
        StringBuilder sb = new StringBuilder();
        for (OrderDetail orderDetail : detailList) {
            sb.append(orderDetail.getSkuName());
        }
        if (sb.length() > 100) {
            orderInfo.setTradeBody(sb.substring(0, 100));
        } else {
            orderInfo.setTradeBody(sb.toString());
        }

        // 创建时间
        orderInfo.setCreateTime(new Date());

        // 失效时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 1);
        orderInfo.setExpireTime(calendar.getTime());

        // 进度状态  也可以获取到订单状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        orderInfoMapper.insert(orderInfo);

        orderInfo.getOrderDetailList().stream().forEach((orderDetail) -> {
            orderDetail.setOrderId(orderInfo.getId());
            orderDetail.setCreateTime(new Date());
            orderDetailMapper.insert(orderDetail);
        });

        // 发送信息到rabbitmq
        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL, MqConst.ROUTING_ORDER_CANCEL, orderInfo.getId(), MqConst.DELAY_TIME);
        return orderInfo.getId();
    }

    //
    @Override
    public String createTradeNo(String userId) {
        String tradeNo = UUID.randomUUID() + userId;

        String key = "user:" + userId + ":tradeCode";
        redisTemplate.opsForValue().set(key, tradeNo);
        return tradeNo;
    }

    // 比较流水号
    @Override
    public boolean checkTradeNo(String tradeNo, String userId) {

        String key = "user:" + userId + ":tradeCode";
        String tradeNoCache = (String) redisTemplate.opsForValue().get(key);
        return tradeNo.equals(tradeNoCache);
    }

    // 删除流水号
    @Override
    public void deleteTradeNo(String userId) {
        String key = "user:" + userId + ":tradeCode";
        redisTemplate.delete(key);
    }

    @Value("${ware.url}")
    String wareUrl;

    // http://localhost:9001/hasStock?skuId=10221&num=2
    @Override
    public boolean checkStock(Long skuId, Integer skuNum) {
        // 库存系统值用到 spring boot 没有 feign 直接用 http协议访问
        String result = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        return "1".equals(result);
    }

    // 根据 Id 关闭订单
    @Override
    public void execExpiredOrder(Long orderInfoId, String flag) {
        this.updateOrderStatus(orderInfoId, ProcessStatus.CLOSED);

        if ("2".equals(flag)) {
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE, MqConst.ROUTING_PAYMENT_CLOSE, orderInfoId);
        }
    }

    // 修改订单状态
    @Override
    public void updateOrderStatus(Long orderInfoId, ProcessStatus processStatus) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderInfoId);
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());

        orderInfoMapper.updateById(orderInfo);
    }

    // 获取 orderInfo对象
    @Override
    public OrderInfo getOrderInfo(Long orderInfoId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderInfoId);
        QueryWrapper<OrderDetail> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", orderInfoId);
        List<OrderDetail> detailList = orderDetailMapper.selectList(wrapper);
        orderInfo.setOrderDetailList(detailList);

        return orderInfo;
    }

    @Override
    public void sendOrderStatus(Long orderId) {
        // 更新订单的状态：
        this.updateOrderStatus(orderId, ProcessStatus.NOTIFIED_WARE);
        // 根据orderId 获取到orderInfo对象 {orderDetailList}
        OrderInfo orderInfo = this.getOrderInfo(orderId);
        //  接口中要的是Json 字符串！ 而且是orderInfo 和orderDetail 中的部分字段！
        //  可以将orderInfo，orderDetail 中的字段存储到一个 Map 集合中！
        Map<String, Object> map = this.orderInfoToMap(orderInfo);

        //  发送消息：
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK, MqConst.ROUTING_WARE_STOCK, JSON.toJSONString(map));
    }


    @Override
    public Map<String, Object> orderInfoToMap(OrderInfo orderInfo) {
        HashMap<String, Object> map = new HashMap<>();

        map.put("orderId", orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay", "2");
        map.put("wareId", orderInfo.getWareId());// 拆分库存时使用！

        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<Map> details = new ArrayList<>();
        for (OrderDetail orderDetail : orderDetailList) {
            HashMap<Object, Object> hashMap = new HashMap<>();
            hashMap.put("skuId", orderDetail.getSkuId());
            hashMap.put("skuNum", orderDetail.getSkuNum());
            hashMap.put("skuName", orderDetail.getSkuName());

            details.add(hashMap);
        }

        map.put("details", details);

        return map;

    }


    // 拆分订单
    @Override
    // [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
    public List<OrderInfo> orderSplit(long orderId, String wareSkuMap) {
        List<OrderInfo> list = new ArrayList<>();

        OrderInfo parentOrderInfo = this.getOrderInfo(orderId); // 原始订单

        List<OrderDetail> orderDetailList = parentOrderInfo.getOrderDetailList();

        List<Map> parseArray = JSON.parseArray(wareSkuMap, Map.class);
        if (parseArray != null && parseArray.size() > 1) {
            for (Map map : parseArray) {
                String wareId = (String) map.get("wareId");
                List<String> skuIds = (List<String>) map.get("skuIds");
                OrderInfo sonOrderInfo = new OrderInfo();

                BeanUtils.copyProperties(parentOrderInfo, sonOrderInfo);
                sonOrderInfo.setId(null); // 防止主键冲突
                sonOrderInfo.setWareId(wareId);
                sonOrderInfo.setParentOrderId(orderId);

                List<OrderDetail> sonDetailList = new ArrayList<>();
                for (OrderDetail orderDetail : orderDetailList) {
                    for (String skuId : skuIds) {
                        if (Long.parseLong(skuId) == orderDetail.getSkuId().longValue()) {
                            sonDetailList.add(orderDetail);
                        }
                    }
                }

                sonOrderInfo.setOrderDetailList(sonDetailList);

                sonOrderInfo.sumTotalAmount();// 子订单的总价格

                this.submitOrder(sonOrderInfo); // 保存子订单

                list.add(sonOrderInfo);
            }
        }

        this.updateOrderStatus(orderId, ProcessStatus.SPLIT);// 修改原始订单状态

        return list;
    }


}
